// 蜂窝蜜造平台生成代码，此文件只生成一次，不需要添加到 .beeignore

package com.fowo.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fowo.api.entity.ListingFather;
import com.fowo.api.entity.NavSellOrder;
import com.fowo.api.entity.StockOut;
import com.fowo.api.inventory.model.*;
import com.fowo.api.inventory.model.form.InventoryOutboundFormVo;
import com.fowo.api.inventory.service.impl.InventoryBusinessServiceImpl;
import com.fowo.api.model.nav.sell.order.NavSellOrderVo;
import com.fowo.api.model.stock.out.StockOutVo;
import com.fowo.api.model.stock.out.product.StockOutProductItemVo;
import com.fowo.api.model.warehousebinrules.WarehouseBinRulesItemVo;
import com.fowo.api.model.warehousebinrules.WarehouseBinRulesSearchParamPo;
import com.fowo.api.sys.annotation.DataActivity;
import com.fowo.api.sys.entity.SysDict;
import com.fowo.api.sys.entity.SysDictItem;
import com.fowo.api.sys.entity.enums.SysDataActivityAction;
import com.fowo.api.sys.mapper.SysDictItemMapper;
import com.fowo.api.sys.mapper.SysDictMapper;
import com.fowo.api.user.model.JwtUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 出库单 服务实现类
 */
@Slf4j
@Service
public class StockOutServiceImpl extends StockOutBaseServiceImpl {

    @Resource
    private WarehouseBinRulesServiceImpl warehouseBinRulesService;
    @Resource
    private SysDictMapper sysDictMapper;
    @Resource
    private SysDictItemMapper sysDictItemMapper;

    @Resource
    private ListingFatherServiceImpl listingFatherService;

    @DataActivity(action = SysDataActivityAction.Add)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long create(StockOutVo model) throws Exception {
        //设置fnsku


        if (model.getStockOutProducts().size() > 0) {
            for (int i = 0; i < model.getStockOutProducts().size(); i++) {
                StockOutProductItemVo x = model.getStockOutProducts().get(i);
                if (x.getFnskuId() != null) {
                    ListingFather byId = listingFatherService.getById(x.getFnskuId());
                    x.setFnsku(byId.getFnsku());
                }
                //次品
                if (x.getProductBadNum() != null && x.getProductBadNum() > 0 && x.getStorageBinBadId() == null) {
                    WarehouseBinRulesSearchParamPo warehouseBinRulesSearchParamPo = new WarehouseBinRulesSearchParamPo();
                    warehouseBinRulesSearchParamPo.setWarehouseId(model.getWarehouse());
                    warehouseBinRulesSearchParamPo.setFnSku(x.getFnsku());
                    warehouseBinRulesSearchParamPo.setWarehouseId(model.getWarehouse());
                    warehouseBinRulesSearchParamPo.setProductId(x.getProductId());
                    warehouseBinRulesSearchParamPo.setShopId(x.getSid());
                    warehouseBinRulesSearchParamPo.setType(2);
                    try {
                        WarehouseBinRulesItemVo search = warehouseBinRulesService.search(warehouseBinRulesSearchParamPo);
                        x.setStorageBinBadId(search.getId());
                    } catch (Exception e) {
                        throw new RuntimeException(e.getMessage());
                    }
                }
                if (x.getStorageBinGoodId() == null) {
                    WarehouseBinRulesSearchParamPo warehouseBinRulesSearchParamPo = new WarehouseBinRulesSearchParamPo();
                    warehouseBinRulesSearchParamPo.setWarehouseId(model.getWarehouse());
                    warehouseBinRulesSearchParamPo.setFnSku(x.getFnsku());
                    warehouseBinRulesSearchParamPo.setWarehouseId(model.getWarehouse());
                    warehouseBinRulesSearchParamPo.setProductId(x.getProductId());
                    warehouseBinRulesSearchParamPo.setShopId(x.getSid());
                    warehouseBinRulesSearchParamPo.setType(1);
                    try {
                        WarehouseBinRulesItemVo search = warehouseBinRulesService.search(warehouseBinRulesSearchParamPo);
                        x.setStorageBinGoodId(search.getId());
                    } catch (Exception e) {
                        throw new RuntimeException(e.getMessage());
                    }
                }
            }
        }
        Long aLong = super.create(model);
        return aLong;
    }

    @DataActivity(action = SysDataActivityAction.Modified)
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(StockOutVo model) throws Exception {
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        StockOut entity = this.getById(model.getId());
        Assert.isTrue(entity.getStatus().equals("CS01"), "已审核不能修改!");
        if (entity == null) {
            throw new Exception("出库单不存在");
        }
        BeanUtils.copyProperties(
                model,
                entity,
                "id",
                "createTime",
                "createUser",
                "lastUpdateTime",
                "lastUpdateUser",
                "orderSn",
                "totalAmount",
                "totalNum",
                "status"
        );
        entity.setLastUpdateTime(new Date());
        if (currentUser != null) {
            entity.setLastUpdateUser(currentUser.getUserId());
        }
        if (this.updateById(entity)) {
            updateAllChilds(model);
            baseMapper.updateCalcFields(entity.getId());
            return true;
        }
        return false;
    }

    @DataActivity(action = SysDataActivityAction.Del)
    @Override
    public boolean delete(Long id) throws Exception {
        StockOut entity = this.getById(id);
        Assert.isTrue(entity.getStatus().equals("CS01"), "已审核不能删除!");
        return this.removeById(id);
    }


    /**
     * 提交
     */
    @DataActivity(
            action = SysDataActivityAction.Other,
            message = "%s执行了提交操作"
    )
    @Override
    public void refer(List<Long> ids) throws Exception {
        Assert.isTrue(CollUtil.isNotEmpty(ids), "参数异常!");
        try {
            List<StockOut> list = new ArrayList<>();
            for (Long id : ids) {
                StockOut stockOut = new StockOut();
                stockOut.setId(id);
                stockOut.setStatus("CS01");
                list.add(stockOut);
            }
            this.updateBatchById(list);
        } catch (Exception ex) {
            log.error("发生异常,异常信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
            throw new RuntimeException("发生异常,信息:" + StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }

    /**
     * 确认出库
     */
    @DataActivity(
            action = SysDataActivityAction.Other,
            message = "%s执行了确认出库操作"
    )
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmationOfDeliverys(Long id) throws Exception {
        StockOutVo vo = getVoById(id);
        InventoryOutboundFormVo formVo = prepareConfirmationOfDeliverys(vo);
        InventoryListReturnVo outbound = inventoryBusinessService.outbound(formVo);
        vo.setStatus("CS02");
        if (ObjUtil.isNotEmpty(outbound.getInventoryStorageVo())) {
            String batchNo = outbound.getInventoryStorageVo().getBatchNo();
            for (StockOutProductItemVo stockOutProduct : vo.getStockOutProducts()) {
                stockOutProduct.setBatchNo(batchNo);
            }
        }
        super.update(vo);
    }


    /**
     * 出库扣减次品
     */
    @DataActivity(
            action = SysDataActivityAction.Other,
            message = "%s执行了出库扣减次品操作"
    )
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void outboundReject(Long id) throws Exception {
        StockOutVo vo = getVoById(id);
        InventoryOutboundFormVo formVo = prepareOutboundReject(vo);
        InventoryListReturnVo outbound = inventoryBusinessService.outbound(formVo);
        vo.setStatus("CS02");
        if (ObjUtil.isNotEmpty(outbound.getInventoryStorageVo())) {
            String batchNo = outbound.getInventoryStorageVo().getBatchNo();
            for (StockOutProductItemVo stockOutProduct : vo.getStockOutProducts()) {
                stockOutProduct.setBatchNo(batchNo);
            }
        }
        super.update(vo);
    }

    /**
     * 准备用于 出库扣减可用 的参数
     */
    @Override
    protected InventoryOutboundFormVo prepareOutboundAvailable(StockOutVo vo) throws Exception {
        if (!"CS01".equals(vo.getStatus())) {
            throw new Exception("当前单据状态不可进行此操作！");
        }
        InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
        formVo.setFrom(TargetTypeEnum.Normal);
        formVo.setFormNum(vo.getOrderSn());
        formVo.setFormOperator(vo.getCreateUser().toString());
        if (ObjectUtils.isEmpty(vo.getWarehouse())) {
            throw new Exception("仓库 为空");
        }
        formVo.setStockId(vo.getWarehouse());
        formVo.setModel(PatternEnum.FIFO);

        final SysDict dict = sysDictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictCode, "SCM00022"));
        final List<SysDictItem> itemList = sysDictItemMapper.selectList(Wrappers.lambdaQuery(SysDictItem.class).eq(SysDictItem::getDictId, dict.getId()));
        final SysDictItem dictItem = itemList.stream().filter(i -> i.getItemValue().equals(vo.getType())).findFirst().get();
        formVo.setDocumentType(dictItem.getItemText());

        for (StockOutProductItemVo stockOutProduct : vo.getStockOutProducts()) {
            if (ObjUtil.isEmpty(stockOutProduct.getStorageBinGoodId())) {
                Long id = SpringUtil.getBean(InventoryBusinessServiceImpl.class).getSearchByWarehouseBin(vo.getWarehouse(), Convert.toStr(stockOutProduct.getSid()), stockOutProduct.getFnsku(), stockOutProduct.getProductId(), 1);
                stockOutProduct.setStorageBinGoodId(id);
            }
            SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
            inventoryItem.setId(stockOutProduct.getProductId());
            InventoryOutboundVo outboundItem = new InventoryOutboundVo();
            outboundItem.setItem(inventoryItem);
            outboundItem.setQty(String.valueOf(stockOutProduct.getProductGoodNum()).equals("null") ? BigDecimal.valueOf(0) : BigDecimal.valueOf(stockOutProduct.getProductGoodNum()));
            outboundItem.setShopId(String.valueOf(stockOutProduct.getSid()).equals("null") ? null : String.valueOf(stockOutProduct.getSid()));
            outboundItem.setFnSku(String.valueOf(stockOutProduct.getFnsku()).equals("null") ? null : String.valueOf(stockOutProduct.getFnsku()));
            Map<Long, Integer> binIds = new HashMap<>();
            binIds.put(stockOutProduct.getStorageBinGoodId(), Integer.parseInt(String.valueOf(stockOutProduct.getProductGoodNum()).equals("null") ? "0" : String.valueOf(stockOutProduct.getProductGoodNum())));
            outboundItem.setBinIds(binIds);
            outboundItem.setFromBinIdsType(TargetTypeEnum.Normal);
            outboundItem.setCustomId(vo.getId());
            outboundItem.setCustomBdId(stockOutProduct.getId());
            formVo.add(outboundItem);
        }
        super.update(vo);
        return formVo;
    }

    /**
     * 准备用于 出库扣减次品 的参数
     */
    protected InventoryOutboundFormVo prepareOutboundReject(StockOutVo vo) throws Exception {
        if (!"CS02".equals(vo.getStatus())) {
            throw new Exception("当前单据状态不可进行此操作！");
        }
        InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
        formVo.setFrom(TargetTypeEnum.Defect);
        formVo.setFormNum(vo.getOrderSn());
        formVo.setFormOperator(vo.getCreateUser().toString());

        final SysDict dict = sysDictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictCode, "SCM00022"));
        final List<SysDictItem> itemList = sysDictItemMapper.selectList(Wrappers.lambdaQuery(SysDictItem.class).eq(SysDictItem::getDictId, dict.getId()));
        final SysDictItem dictItem = itemList.stream().filter(i -> i.getItemValue().equals(vo.getType())).findFirst().get();
        formVo.setDocumentType(dictItem.getItemText());

        if (ObjectUtils.isEmpty(vo.getWarehouse())) {
            throw new Exception("仓库 为空");
        }
        formVo.setStockId(vo.getWarehouse());
        formVo.setModel(PatternEnum.FIFO);
        for (StockOutProductItemVo stockOutProduct : vo.getStockOutProducts()) {
            if (ObjUtil.isEmpty(stockOutProduct.getStorageBinBadId())) {
                Long id = SpringUtil.getBean(InventoryBusinessServiceImpl.class).getSearchByWarehouseBin(vo.getWarehouse(), Convert.toStr(stockOutProduct.getSid()), stockOutProduct.getFnsku(), stockOutProduct.getProductId(), 2);
                stockOutProduct.setStorageBinBadId(id);
            }
            SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
            inventoryItem.setId(stockOutProduct.getProductId());
            InventoryOutboundVo outboundItem = new InventoryOutboundVo();
            outboundItem.setItem(inventoryItem);
            outboundItem.setQty(String.valueOf(stockOutProduct.getProductBadNum()).equals("null") ? BigDecimal.valueOf(0) : BigDecimal.valueOf(stockOutProduct.getProductBadNum()));
            outboundItem.setShopId(String.valueOf(stockOutProduct.getSid()).equals("null") ? null : String.valueOf(stockOutProduct.getSid()));
            outboundItem.setFnSku(String.valueOf(stockOutProduct.getFnsku()).equals("null") ? null : String.valueOf(stockOutProduct.getFnsku()));
            Map<Long, Integer> binIds = new HashMap<>();
            binIds.put(stockOutProduct.getStorageBinBadId(), Integer.parseInt(String.valueOf(stockOutProduct.getProductBadNum()).equals("null") ? "0" : String.valueOf(stockOutProduct.getProductBadNum())));
            outboundItem.setBinIds(binIds);
            outboundItem.setFromBinIdsType(TargetTypeEnum.Normal);
            outboundItem.setCustomId(vo.getId());
            outboundItem.setCustomBdId(stockOutProduct.getId());
            formVo.add(outboundItem);
        }
        super.update(vo);
        return formVo;
    }
}
